/*
** $Id: lparser.c,v 2.40 2005/12/22 16:19:56 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/


#include <string.h>

#define lparser_c
#define LUA_CORE

#include "lua.h"

#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"


#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)

#define getlocvar(fs, i)	((fs)->f->locvars[(fs)->actvar[i]])

#define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) errorlimit(fs,l,m)

/*
** nodes for block list (list of active blocks)
*/
typedef struct BlockCnt {
	struct BlockCnt *previous;  /* chain */
	int breaklist;  /* list of jumps out of this loop */
	lu_byte nactvar;  /* # active locals outside the breakable structure */
	lu_byte upval;  /* true if some variable in the block is an upvalue */
	lu_byte isbreakable;  /* true if `block' is a loop */
} BlockCnt;



/*
** prototypes for recursive non-terminal functions
*/
static void chunk (LexState *ls);
static void expr (LexState *ls, expdesc *v);


static void anchor_token (LexState *ls) {
	if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
		TString *ts = ls->t.seminfo.ts;
		luaX_newstring(ls, getstr(ts), ts->tsv.len);
	}
}


static void error_expected (LexState *ls, int token) {
	luaX_syntaxerror(ls,
		luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token)));
}


static void errorlimit (FuncState *fs, int limit, const char *what) {
	const char *msg = (fs->f->linedefined == 0) ?
		luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
	luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
		fs->f->linedefined, limit, what);
	luaX_lexerror(fs->ls, msg, 0);
}


static int testnext (LexState *ls, int c) {
	if (ls->t.token == c) {
		luaX_next(ls);
		return 1;
	}
	else return 0;
}


static void check (LexState *ls, int c) {
	if (ls->t.token != c)
		error_expected(ls, c);
}

static void checknext (LexState *ls, int c) {
	check(ls, c);
	luaX_next(ls);
}


#define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }



static void check_match (LexState *ls, int what, int who, int where) {
	if (!testnext(ls, what)) {
		if (where == ls->linenumber)
			error_expected(ls, what);
		else {
			luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
				LUA_QS " expected (to close " LUA_QS " at line %d)",
				luaX_token2str(ls, what), luaX_token2str(ls, who), where));
		}
	}
}


static TString *str_checkname (LexState *ls) {
	TString *ts;
	check(ls, TK_NAME);
	ts = ls->t.seminfo.ts;
	luaX_next(ls);
	return ts;
}


static void init_exp (expdesc *e, expkind k, int i) {
	e->f = e->t = NO_JUMP;
	e->k = k;
	e->u.s.info = i;
}


static void codestring (LexState *ls, expdesc *e, TString *s) {
	init_exp(e, VK, luaK_stringK(ls->fs, s));
}


static void checkname(LexState *ls, expdesc *e) {
	codestring(ls, e, str_checkname(ls));
}


static int registerlocalvar (LexState *ls, TString *varname) {
	FuncState *fs = ls->fs;
	Proto *f = fs->f;
	int oldsize = f->sizelocvars;
	luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
		LocVar, SHRT_MAX, "too many local variables");
	while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
	f->locvars[fs->nlocvars].varname = varname;
	luaC_objbarrier(ls->L, f, varname);
	return fs->nlocvars++;
}


#define new_localvarliteral(ls,v,n) \
	new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)


static void new_localvar (LexState *ls, TString *name, int n) {
	FuncState *fs = ls->fs;
	luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
	fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
}


static void adjustlocalvars (LexState *ls, int nvars) {
	FuncState *fs = ls->fs;
	fs->nactvar = cast_byte(fs->nactvar + nvars);
	for (; nvars; nvars--) {
		getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc;
	}
}


static void removevars (LexState *ls, int tolevel) {
	FuncState *fs = ls->fs;
	while (fs->nactvar > tolevel)
		getlocvar(fs, --fs->nactvar).endpc = fs->pc;
}


static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
	int i;
	Proto *f = fs->f;
	int oldsize = f->sizeupvalues;
	for (i=0; i<f->nups; i++) {
		if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) {
			lua_assert(f->upvalues[i] == name);
			return i;
		}
	}
	/* new one */
	luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues");
	luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
		TString *, MAX_INT, "");
	while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
	f->upvalues[f->nups] = name;
	luaC_objbarrier(fs->L, f, name);
	lua_assert(v->k == VLOCAL || v->k == VUPVAL);
	fs->upvalues[f->nups].k = cast_byte(v->k);
	fs->upvalues[f->nups].info = cast_byte(v->u.s.info);
	return f->nups++;
}


static int searchvar (FuncState *fs, TString *n) {
	int i;
	for (i=fs->nactvar-1; i >= 0; i--) {
		if (n == getlocvar(fs, i).varname)
			return i;
	}
	return -1;  /* not found */
}


static void markupval (FuncState *fs, int level) {
	BlockCnt *bl = fs->bl;
	while (bl && bl->nactvar > level) bl = bl->previous;
	if (bl) bl->upval = 1;
}


static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
	if (fs == NULL) {  /* no more levels? */
		init_exp(var, VGLOBAL, NO_REG);  /* default is global variable */
		return VGLOBAL;
	}
	else {
		int v = searchvar(fs, n);  /* look up at current level */
		if (v >= 0) {
			init_exp(var, VLOCAL, v);
			if (!base)
				markupval(fs, v);  /* local will be used as an upval */
			return VLOCAL;
		}
		else {  /* not found at current level; try upper one */
			if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
				return VGLOBAL;
			var->u.s.info = indexupvalue(fs, n, var);  /* else was LOCAL or UPVAL */
			var->k = VUPVAL;  /* upvalue in this level */
			return VUPVAL;
		}
	}
}


static void singlevar (LexState *ls, expdesc *var) {
	TString *varname = str_checkname(ls);
	FuncState *fs = ls->fs;
	if (singlevaraux(fs, varname, var, 1) == VGLOBAL)
		var->u.s.info = luaK_stringK(fs, varname);  /* info points to global name */
}


static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
	FuncState *fs = ls->fs;
	int extra = nvars - nexps;
	if (hasmultret(e->k)) {
		extra++;  /* includes call itself */
		if (extra < 0) extra = 0;
		luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
		if (extra > 1) luaK_reserveregs(fs, extra-1);
	}
	else {
		if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
		if (extra > 0) {
			int reg = fs->freereg;
			luaK_reserveregs(fs, extra);
			luaK_nil(fs, reg, extra);
		}
	}
}


static void enterlevel (LexState *ls) {
	if (++ls->L->nCcalls > LUAI_MAXCCALLS)
		luaX_lexerror(ls, "chunk has too many syntax levels", 0);
}


#define leavelevel(ls)	((ls)->L->nCcalls--)


static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
	bl->breaklist = NO_JUMP;
	bl->isbreakable = isbreakable;
	bl->nactvar = fs->nactvar;
	bl->upval = 0;
	bl->previous = fs->bl;
	fs->bl = bl;
	lua_assert(fs->freereg == fs->nactvar);
}


static void leaveblock (FuncState *fs) {
	BlockCnt *bl = fs->bl;
	fs->bl = bl->previous;
	removevars(fs->ls, bl->nactvar);
	if (bl->upval)
		luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
	lua_assert(!bl->isbreakable || !bl->upval);  /* loops have no body */
	lua_assert(bl->nactvar == fs->nactvar);
	fs->freereg = fs->nactvar;  /* free registers */
	luaK_patchtohere(fs, bl->breaklist);
}


static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
	FuncState *fs = ls->fs;
	Proto *f = fs->f;
	int oldsize = f->sizep;
	int i;
	luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
		MAXARG_Bx, "constant table overflow");
	while (oldsize < f->sizep) f->p[oldsize++] = NULL;
	f->p[fs->np++] = func->f;
	luaC_objbarrier(ls->L, f, func->f);
	init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
	for (i=0; i<func->f->nups; i++) {
		OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
		luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
	}
}


static void open_func (LexState *ls, FuncState *fs) {
	lua_State *L = ls->L;
	Proto *f = luaF_newproto(L);
	fs->f = f;
	fs->prev = ls->fs;  /* linked list of funcstates */
	fs->ls = ls;
	fs->L = L;
	ls->fs = fs;
	fs->pc = 0;
	fs->lasttarget = -1;
	fs->jpc = NO_JUMP;
	fs->freereg = 0;
	fs->nk = 0;
	fs->np = 0;
	fs->nlocvars = 0;
	fs->nactvar = 0;
	fs->bl = NULL;
	f->source = ls->source;
	f->maxstacksize = 2;  /* registers 0/1 are always valid */
	fs->h = luaH_new(L, 0, 0);
	/* anchor table of constants and prototype (to avoid being collected) */
	sethvalue2s(L, L->top, fs->h);
	incr_top(L);
	setptvalue2s(L, L->top, f);
	incr_top(L);
}


static void close_func (LexState *ls) {
	lua_State *L = ls->L;
	FuncState *fs = ls->fs;
	Proto *f = fs->f;
	removevars(ls, 0);
	luaK_ret(fs, 0, 0);  /* final return */
	luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
	f->sizecode = fs->pc;
	luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
	f->sizelineinfo = fs->pc;
	luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
	f->sizek = fs->nk;
	luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
	f->sizep = fs->np;
	luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
	f->sizelocvars = fs->nlocvars;
	luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
	f->sizeupvalues = f->nups;
	lua_assert(luaG_checkcode(f));
	lua_assert(fs->bl == NULL);
	ls->fs = fs->prev;
	L->top -= 2;  /* remove table and prototype from the stack */
	/* last token read was anchored in defunct function; must reanchor it */
	if (fs) anchor_token(ls);
}


Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
	struct LexState lexstate;
	struct FuncState funcstate;
	lexstate.buff = buff;
	luaX_setinput(L, &lexstate, z, luaS_new(L, name));
	open_func(&lexstate, &funcstate);
	funcstate.f->is_vararg = VARARG_ISVARARG;  /* main func. is always vararg */
	luaX_next(&lexstate);  /* read first token */
	chunk(&lexstate);
	check(&lexstate, TK_EOS);
	close_func(&lexstate);
	lua_assert(funcstate.prev == NULL);
	lua_assert(funcstate.f->nups == 0);
	lua_assert(lexstate.fs == NULL);
	return funcstate.f;
}



/*============================================================*/
/* GRAMMAR RULES */
/*============================================================*/


static void field (LexState *ls, expdesc *v) {
	/* field -> ['.' | ':'] NAME */
	FuncState *fs = ls->fs;
	expdesc key;
	luaK_exp2anyreg(fs, v);
	luaX_next(ls);  /* skip the dot or colon */
	checkname(ls, &key);
	luaK_indexed(fs, v, &key);
}


static void yindex (LexState *ls, expdesc *v) {
	/* index -> '[' expr ']' */
	luaX_next(ls);  /* skip the '[' */
	expr(ls, v);
	luaK_exp2val(ls->fs, v);
	checknext(ls, ']');
}


/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/


struct ConsControl {
	expdesc v;  /* last list item read */
	expdesc *t;  /* table descriptor */
	int nh;  /* total number of `record' elements */
	int na;  /* total number of array elements */
	int tostore;  /* number of array elements pending to be stored */
};


static void recfield (LexState *ls, struct ConsControl *cc) {
	/* recfield -> (NAME | `['exp1`]') = exp1 */
	FuncState *fs = ls->fs;
	int reg = ls->fs->freereg;
	expdesc key, val;
	if (ls->t.token == TK_NAME) {
		luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
		checkname(ls, &key);
	}
	else  /* ls->t.token == '[' */
		yindex(ls, &key);
	cc->nh++;
	checknext(ls, '=');
	luaK_exp2RK(fs, &key);
	expr(ls, &val);
	luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, luaK_exp2RK(fs, &key),
		luaK_exp2RK(fs, &val));
	fs->freereg = reg;  /* free registers */
}


static void closelistfield (FuncState *fs, struct ConsControl *cc) {
	if (cc->v.k == VVOID) return;  /* there is no list item */
	luaK_exp2nextreg(fs, &cc->v);
	cc->v.k = VVOID;
	if (cc->tostore == LFIELDS_PER_FLUSH) {
		luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);  /* flush */
		cc->tostore = 0;  /* no more items pending */
	}
}


static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
	if (cc->tostore == 0) return;
	if (hasmultret(cc->v.k)) {
		luaK_setmultret(fs, &cc->v);
		luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET);
		cc->na--;  /* do not count last expression (unknown number of elements) */
	}
	else {
		if (cc->v.k != VVOID)
			luaK_exp2nextreg(fs, &cc->v);
		luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);
	}
}


static void listfield (LexState *ls, struct ConsControl *cc) {
	expr(ls, &cc->v);
	luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor");
	cc->na++;
	cc->tostore++;
}


static void constructor (LexState *ls, expdesc *t) {
	/* constructor -> ?? */
	FuncState *fs = ls->fs;
	int line = ls->linenumber;
	int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
	struct ConsControl cc;
	cc.na = cc.nh = cc.tostore = 0;
	cc.t = t;
	init_exp(t, VRELOCABLE, pc);
	init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
	luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top (for gc) */
	checknext(ls, '{');
	do {
		lua_assert(cc.v.k == VVOID || cc.tostore > 0);
		if (ls->t.token == '}') break;
		closelistfield(fs, &cc);
		switch(ls->t.token) {
	  case TK_NAME: {  /* may be listfields or recfields */
		  luaX_lookahead(ls);
		  if (ls->lookahead.token != '=')  /* expression? */
			  listfield(ls, &cc);
		  else
			  recfield(ls, &cc);
		  break;
					}
	  case '[': {  /* constructor_item -> recfield */
		  recfield(ls, &cc);
		  break;
				}
	  default: {  /* constructor_part -> listfield */
		  listfield(ls, &cc);
		  break;
			   }
		}
	} while (testnext(ls, ',') || testnext(ls, ';'));
	check_match(ls, '}', '{', line);
	lastlistfield(fs, &cc);
	SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
	SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
}

/* }====================================================================== */



static void parlist (LexState *ls) {
	/* parlist -> [ param { `,' param } ] */
	FuncState *fs = ls->fs;
	Proto *f = fs->f;
	int nparams = 0;
	f->is_vararg = 0;
	if (ls->t.token != ')') {  /* is `parlist' not empty? */
		do {
			switch (ls->t.token) {
		case TK_NAME: {  /* param -> NAME */
			new_localvar(ls, str_checkname(ls), nparams++);
			break;
					  }
		case TK_DOTS: {  /* param -> `...' */
			luaX_next(ls);
#if defined(LUA_COMPAT_VARARG)
			/* use `arg' as default name */
			new_localvarliteral(ls, "arg", nparams++);
			f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
#endif
			f->is_vararg |= VARARG_ISVARARG;
			break;
					  }
		default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
			}
		} while (!f->is_vararg && testnext(ls, ','));
	}
	adjustlocalvars(ls, nparams);
	f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG));
	luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */
}


static void body (LexState *ls, expdesc *e, int needself, int line) {
	/* body ->  `(' parlist `)' chunk END */
	FuncState new_fs;
	open_func(ls, &new_fs);
	new_fs.f->linedefined = line;
	checknext(ls, '(');
	if (needself) {
		new_localvarliteral(ls, "self", 0);
		adjustlocalvars(ls, 1);
	}
	parlist(ls);
	checknext(ls, ')');
	chunk(ls);
	new_fs.f->lastlinedefined = ls->linenumber;
	check_match(ls, TK_END, TK_FUNCTION, line);
	close_func(ls);
	pushclosure(ls, &new_fs, e);
}


static int explist1 (LexState *ls, expdesc *v) {
	/* explist1 -> expr { `,' expr } */
	int n = 1;  /* at least one expression */
	expr(ls, v);
	while (testnext(ls, ',')) {
		luaK_exp2nextreg(ls->fs, v);
		expr(ls, v);
		n++;
	}
	return n;
}


static void funcargs (LexState *ls, expdesc *f) {
	FuncState *fs = ls->fs;
	expdesc args;
	int base, nparams;
	int line = ls->linenumber;
	switch (ls->t.token) {
	case '(': {  /* funcargs -> `(' [ explist1 ] `)' */
		if (line != ls->lastline)
			luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
		luaX_next(ls);
		if (ls->t.token == ')')  /* arg list is empty? */
			args.k = VVOID;
		else {
			explist1(ls, &args);
			luaK_setmultret(fs, &args);
		}
		check_match(ls, ')', '(', line);
		break;
			  }
	case '{': {  /* funcargs -> constructor */
		constructor(ls, &args);
		break;
			  }
	case TK_STRING: {  /* funcargs -> STRING */
		codestring(ls, &args, ls->t.seminfo.ts);
		luaX_next(ls);  /* must use `seminfo' before `next' */
		break;
					}
	default: {
		luaX_syntaxerror(ls, "function arguments expected");
		return;
			 }
	}
	lua_assert(f->k == VNONRELOC);
	base = f->u.s.info;  /* base register for call */
	if (hasmultret(args.k))
		nparams = LUA_MULTRET;  /* open call */
	else {
		if (args.k != VVOID)
			luaK_exp2nextreg(fs, &args);  /* close last argument */
		nparams = fs->freereg - (base+1);
	}
	init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
	luaK_fixline(fs, line);
	fs->freereg = base+1;  /* call remove function and arguments and leaves
						   (unless changed) one result */
}




/*
** {======================================================================
** Expression parsing
** =======================================================================
*/


static void prefixexp (LexState *ls, expdesc *v) {
	/* prefixexp -> NAME | '(' expr ')' */
	switch (ls->t.token) {
	case '(': {
		int line = ls->linenumber;
		luaX_next(ls);
		expr(ls, v);
		check_match(ls, ')', '(', line);
		luaK_dischargevars(ls->fs, v);
		return;
			  }
	case TK_NAME: {
		singlevar(ls, v);
		return;
				  }
	default: {
		luaX_syntaxerror(ls, "unexpected symbol");
		return;
			 }
	}
}


static void primaryexp (LexState *ls, expdesc *v) {
	/* primaryexp ->
	prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
	FuncState *fs = ls->fs;
	prefixexp(ls, v);
	for (;;) {
		switch (ls->t.token) {
	  case '.': {  /* field */
		  field(ls, v);
		  break;
				}
	  case '[': {  /* `[' exp1 `]' */
		  expdesc key;
		  luaK_exp2anyreg(fs, v);
		  yindex(ls, &key);
		  luaK_indexed(fs, v, &key);
		  break;
				}
	  case ':': {  /* `:' NAME funcargs */
		  expdesc key;
		  luaX_next(ls);
		  checkname(ls, &key);
		  luaK_self(fs, v, &key);
		  funcargs(ls, v);
		  break;
				}
	  case '(': case TK_STRING: case '{': {  /* funcargs */
		  luaK_exp2nextreg(fs, v);
		  funcargs(ls, v);
		  break;
				}
	  default: return;
		}
	}
}


static void simpleexp (LexState *ls, expdesc *v) {
	/* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
	constructor | FUNCTION body | primaryexp */
	switch (ls->t.token) {
	case TK_NUMBER: {
		init_exp(v, VKNUM, 0);
		v->u.nval = ls->t.seminfo.r;
		break;
					}
	case TK_STRING: {
		codestring(ls, v, ls->t.seminfo.ts);
		break;
					}
	case TK_NIL: {
		init_exp(v, VNIL, 0);
		break;
				 }
	case TK_TRUE: {
		init_exp(v, VTRUE, 0);
		break;
				  }
	case TK_FALSE: {
		init_exp(v, VFALSE, 0);
		break;
				   }
	case TK_DOTS: {  /* vararg */
		FuncState *fs = ls->fs;
		check_condition(ls, fs->f->is_vararg,
			"cannot use " LUA_QL("...") " outside a vararg function");
		fs->f->is_vararg &= ~VARARG_NEEDSARG;  /* don't need 'arg' */
		init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
		break;
				  }
	case '{': {  /* constructor */
		constructor(ls, v);
		return;
			  }
	case TK_FUNCTION: {
		luaX_next(ls);
		body(ls, v, 0, ls->linenumber);
		return;
					  }
	default: {
		primaryexp(ls, v);
		return;
			 }
	}
	luaX_next(ls);
}


static UnOpr getunopr (int op) {
	switch (op) {
	case TK_NOT: return OPR_NOT;
	case '-': return OPR_MINUS;
	case '#': return OPR_LEN;
	default: return OPR_NOUNOPR;
	}
}


static BinOpr getbinopr (int op) {
	switch (op) {
	case '+': return OPR_ADD;
	case '-': return OPR_SUB;
	case '*': return OPR_MUL;
	case '/': return OPR_DIV;
	case '%': return OPR_MOD;
	case '^': return OPR_POW;
	case TK_CONCAT: return OPR_CONCAT;
	case TK_NE: return OPR_NE;
	case TK_EQ: return OPR_EQ;
	case '<': return OPR_LT;
	case TK_LE: return OPR_LE;
	case '>': return OPR_GT;
	case TK_GE: return OPR_GE;
	case TK_AND: return OPR_AND;
	case TK_OR: return OPR_OR;
	default: return OPR_NOBINOPR;
	}
}


static const struct {
	lu_byte left;  /* left priority for each binary operator */
	lu_byte right; /* right priority */
} priority[] = {  /* ORDER OPR */
	{6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `/' `%' */
	{10, 9}, {5, 4},                 /* power and concat (right associative) */
	{3, 3}, {3, 3},                  /* equality and inequality */
	{3, 3}, {3, 3}, {3, 3}, {3, 3},  /* order */
	{2, 2}, {1, 1}                   /* logical (and/or) */
};

#define UNARY_PRIORITY	8  /* priority for unary operators */


/*
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit'
*/
static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
	BinOpr op;
	UnOpr uop;
	enterlevel(ls);
	uop = getunopr(ls->t.token);
	if (uop != OPR_NOUNOPR) {
		luaX_next(ls);
		subexpr(ls, v, UNARY_PRIORITY);
		luaK_prefix(ls->fs, uop, v);
	}
	else simpleexp(ls, v);
	/* expand while operators have priorities higher than `limit' */
	op = getbinopr(ls->t.token);
	while (op != OPR_NOBINOPR && priority[op].left > limit) {
		expdesc v2;
		BinOpr nextop;
		luaX_next(ls);
		luaK_infix(ls->fs, op, v);
		/* read sub-expression with higher priority */
		nextop = subexpr(ls, &v2, priority[op].right);
		luaK_posfix(ls->fs, op, v, &v2);
		op = nextop;
	}
	leavelevel(ls);
	return op;  /* return first untreated operator */
}


static void expr (LexState *ls, expdesc *v) {
	subexpr(ls, v, 0);
}

/* }==================================================================== */



/*
** {======================================================================
** Rules for Statements
** =======================================================================
*/


static int block_follow (int token) {
	switch (token) {
	case TK_ELSE: case TK_ELSEIF: case TK_END:
	case TK_UNTIL: case TK_EOS:
		return 1;
	default: return 0;
	}
}


static void block (LexState *ls) {
	/* block -> chunk */
	FuncState *fs = ls->fs;
	BlockCnt bl;
	enterblock(fs, &bl, 0);
	chunk(ls);
	lua_assert(bl.breaklist == NO_JUMP);
	leaveblock(fs);
}


/*
** structure to chain all variables in the left-hand side of an
** assignment
*/
struct LHS_assign {
	struct LHS_assign *prev;
	expdesc v;  /* variable (global, local, upvalue, or indexed) */
};


/*
** check whether, in an assignment to a local variable, the local variable
** is needed in a previous assignment (to a table). If so, save original
** local value in a safe place and use this safe copy in the previous
** assignment.
*/
static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
	FuncState *fs = ls->fs;
	int extra = fs->freereg;  /* eventual position to save local variable */
	int conflict = 0;
	for (; lh; lh = lh->prev) {
		if (lh->v.k == VINDEXED) {
			if (lh->v.u.s.info == v->u.s.info) {  /* conflict? */
				conflict = 1;
				lh->v.u.s.info = extra;  /* previous assignment will use safe copy */
			}
			if (lh->v.u.s.aux == v->u.s.info) {  /* conflict? */
				conflict = 1;
				lh->v.u.s.aux = extra;  /* previous assignment will use safe copy */
			}
		}
	}
	if (conflict) {
		luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0);  /* make copy */
		luaK_reserveregs(fs, 1);
	}
}


static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
	expdesc e;
	check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
		"syntax error");
	if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */
		struct LHS_assign nv;
		nv.prev = lh;
		primaryexp(ls, &nv.v);
		if (nv.v.k == VLOCAL)
			check_conflict(ls, lh, &nv.v);
		assignment(ls, &nv, nvars+1);
	}
	else {  /* assignment -> `=' explist1 */
		int nexps;
		checknext(ls, '=');
		nexps = explist1(ls, &e);
		if (nexps != nvars) {
			adjust_assign(ls, nvars, nexps, &e);
			if (nexps > nvars)
				ls->fs->freereg -= nexps - nvars;  /* remove extra values */
		}
		else {
			luaK_setoneret(ls->fs, &e);  /* close last expression */
			luaK_storevar(ls->fs, &lh->v, &e);
			return;  /* avoid default */
		}
	}
	init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
	luaK_storevar(ls->fs, &lh->v, &e);
}


static int cond (LexState *ls) {
	/* cond -> exp */
	expdesc v;
	expr(ls, &v);  /* read condition */
	if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */
	luaK_goiftrue(ls->fs, &v);
	return v.f;
}


static void breakstat (LexState *ls) {
	FuncState *fs = ls->fs;
	BlockCnt *bl = fs->bl;
	int upval = 0;
	while (bl && !bl->isbreakable) {
		upval |= bl->upval;
		bl = bl->previous;
	}
	if (!bl)
		luaX_syntaxerror(ls, "no loop to break");
	if (upval)
		luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
	luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
}


static void whilestat (LexState *ls, int line) {
	/* whilestat -> WHILE cond DO block END */
	FuncState *fs = ls->fs;
	int whileinit;
	int condexit;
	BlockCnt bl;
	luaX_next(ls);  /* skip WHILE */
	whileinit = luaK_getlabel(fs);
	condexit = cond(ls);
	enterblock(fs, &bl, 1);
	checknext(ls, TK_DO);
	block(ls);
	luaK_patchlist(fs, luaK_jump(fs), whileinit);
	check_match(ls, TK_END, TK_WHILE, line);
	leaveblock(fs);
	luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */
}


static void repeatstat (LexState *ls, int line) {
	/* repeatstat -> REPEAT block UNTIL cond */
	int condexit;
	FuncState *fs = ls->fs;
	int repeat_init = luaK_getlabel(fs);
	BlockCnt bl1, bl2;
	enterblock(fs, &bl1, 1);  /* loop block */
	enterblock(fs, &bl2, 0);  /* scope block */
	luaX_next(ls);  /* skip REPEAT */
	chunk(ls);
	check_match(ls, TK_UNTIL, TK_REPEAT, line);
	condexit = cond(ls);  /* read condition (inside scope block) */
	if (!bl2.upval) {  /* no upvalues? */
		leaveblock(fs);  /* finish scope */
		luaK_patchlist(ls->fs, condexit, repeat_init);  /* close the loop */
	}
	else {  /* complete semantics when there are upvalues */
		breakstat(ls);  /* if condition then break */
		luaK_patchtohere(ls->fs, condexit);  /* else... */
		leaveblock(fs);  /* finish scope... */
		luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init);  /* and repeat */
	}
	leaveblock(fs);  /* finish loop */
}


static int exp1 (LexState *ls) {
	expdesc e;
	int k;
	expr(ls, &e);
	k = e.k;
	luaK_exp2nextreg(ls->fs, &e);
	return k;
}


static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
	/* forbody -> DO block */
	BlockCnt bl;
	FuncState *fs = ls->fs;
	int prep, endfor;
	adjustlocalvars(ls, 3);  /* control variables */
	checknext(ls, TK_DO);
	prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
	enterblock(fs, &bl, 0);  /* scope for declared variables */
	adjustlocalvars(ls, nvars);
	luaK_reserveregs(fs, nvars);
	block(ls);
	leaveblock(fs);  /* end of scope for declared variables */
	luaK_patchtohere(fs, prep);
	endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
		luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
	luaK_fixline(fs, line);  /* pretend that `OP_FOR' starts the loop */
	luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
}


static void fornum (LexState *ls, TString *varname, int line) {
	/* fornum -> NAME = exp1,exp1[,exp1] forbody */
	FuncState *fs = ls->fs;
	int base = fs->freereg;
	new_localvarliteral(ls, "(for index)", 0);
	new_localvarliteral(ls, "(for limit)", 1);
	new_localvarliteral(ls, "(for step)", 2);
	new_localvar(ls, varname, 3);
	checknext(ls, '=');
	exp1(ls);  /* initial value */
	checknext(ls, ',');
	exp1(ls);  /* limit */
	if (testnext(ls, ','))
		exp1(ls);  /* optional step */
	else {  /* default step = 1 */
		luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
		luaK_reserveregs(fs, 1);
	}
	forbody(ls, base, line, 1, 1);
}


static void forlist (LexState *ls, TString *indexname) {
	/* forlist -> NAME {,NAME} IN explist1 forbody */
	FuncState *fs = ls->fs;
	expdesc e;
	int nvars = 0;
	int line;
	int base = fs->freereg;
	/* create control variables */
	new_localvarliteral(ls, "(for generator)", nvars++);
	new_localvarliteral(ls, "(for state)", nvars++);
	new_localvarliteral(ls, "(for control)", nvars++);
	/* create declared variables */
	new_localvar(ls, indexname, nvars++);
	while (testnext(ls, ','))
		new_localvar(ls, str_checkname(ls), nvars++);
	checknext(ls, TK_IN);
	line = ls->linenumber;
	adjust_assign(ls, 3, explist1(ls, &e), &e);
	luaK_checkstack(fs, 3);  /* extra space to call generator */
	forbody(ls, base, line, nvars - 3, 0);
}


static void forstat (LexState *ls, int line) {
	/* forstat -> FOR (fornum | forlist) END */
	FuncState *fs = ls->fs;
	TString *varname;
	BlockCnt bl;
	enterblock(fs, &bl, 1);  /* scope for loop and control variables */
	luaX_next(ls);  /* skip `for' */
	varname = str_checkname(ls);  /* first variable name */
	switch (ls->t.token) {
	case '=': fornum(ls, varname, line); break;
	case ',': case TK_IN: forlist(ls, varname); break;
	default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
	}
	check_match(ls, TK_END, TK_FOR, line);
	leaveblock(fs);  /* loop scope (`break' jumps to this point) */
}


static int test_then_block (LexState *ls) {
	/* test_then_block -> [IF | ELSEIF] cond THEN block */
	int condexit;
	luaX_next(ls);  /* skip IF or ELSEIF */
	condexit = cond(ls);
	checknext(ls, TK_THEN);
	block(ls);  /* `then' part */
	return condexit;
}


static void ifstat (LexState *ls, int line) {
	/* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
	FuncState *fs = ls->fs;
	int flist;
	int escapelist = NO_JUMP;
	flist = test_then_block(ls);  /* IF cond THEN block */
	while (ls->t.token == TK_ELSEIF) {
		luaK_concat(fs, &escapelist, luaK_jump(fs));
		luaK_patchtohere(fs, flist);
		flist = test_then_block(ls);  /* ELSEIF cond THEN block */
	}
	if (ls->t.token == TK_ELSE) {
		luaK_concat(fs, &escapelist, luaK_jump(fs));
		luaK_patchtohere(fs, flist);
		luaX_next(ls);  /* skip ELSE (after patch, for correct line info) */
		block(ls);  /* `else' part */
	}
	else
		luaK_concat(fs, &escapelist, flist);
	luaK_patchtohere(fs, escapelist);
	check_match(ls, TK_END, TK_IF, line);
}


static void localfunc (LexState *ls) {
	expdesc v, b;
	FuncState *fs = ls->fs;
	new_localvar(ls, str_checkname(ls), 0);
	init_exp(&v, VLOCAL, fs->freereg);
	luaK_reserveregs(fs, 1);
	adjustlocalvars(ls, 1);
	body(ls, &b, 0, ls->linenumber);
	luaK_storevar(fs, &v, &b);
	/* debug information will only see the variable after this point! */
	getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
}


static void localstat (LexState *ls) {
	/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
	int nvars = 0;
	int nexps;
	expdesc e;
	do {
		new_localvar(ls, str_checkname(ls), nvars++);
	} while (testnext(ls, ','));
	if (testnext(ls, '='))
		nexps = explist1(ls, &e);
	else {
		e.k = VVOID;
		nexps = 0;
	}
	adjust_assign(ls, nvars, nexps, &e);
	adjustlocalvars(ls, nvars);
}


static int funcname (LexState *ls, expdesc *v) {
	/* funcname -> NAME {field} [`:' NAME] */
	int needself = 0;
	singlevar(ls, v);
	while (ls->t.token == '.')
		field(ls, v);
	if (ls->t.token == ':') {
		needself = 1;
		field(ls, v);
	}
	return needself;
}


static void funcstat (LexState *ls, int line) {
	/* funcstat -> FUNCTION funcname body */
	int needself;
	expdesc v, b;
	luaX_next(ls);  /* skip FUNCTION */
	needself = funcname(ls, &v);
	body(ls, &b, needself, line);
	luaK_storevar(ls->fs, &v, &b);
	luaK_fixline(ls->fs, line);  /* definition `happens' in the first line */
}


static void exprstat (LexState *ls) {
	/* stat -> func | assignment */
	FuncState *fs = ls->fs;
	struct LHS_assign v;
	primaryexp(ls, &v.v);
	if (v.v.k == VCALL)  /* stat -> func */
		SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */
	else {  /* stat -> assignment */
		v.prev = NULL;
		assignment(ls, &v, 1);
	}
}


static void retstat (LexState *ls) {
	/* stat -> RETURN explist */
	FuncState *fs = ls->fs;
	expdesc e;
	int first, nret;  /* registers with returned values */
	luaX_next(ls);  /* skip RETURN */
	if (block_follow(ls->t.token) || ls->t.token == ';')
		first = nret = 0;  /* return no values */
	else {
		nret = explist1(ls, &e);  /* optional return values */
		if (hasmultret(e.k)) {
			luaK_setmultret(fs, &e);
			if (e.k == VCALL && nret == 1) {  /* tail call? */
				SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
				lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
			}
			first = fs->nactvar;
			nret = LUA_MULTRET;  /* return all values */
		}
		else {
			if (nret == 1)  /* only one single value? */
				first = luaK_exp2anyreg(fs, &e);
			else {
				luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
				first = fs->nactvar;  /* return all `active' values */
				lua_assert(nret == fs->freereg - first);
			}
		}
	}
	luaK_ret(fs, first, nret);
}


static int statement (LexState *ls) {
	int line = ls->linenumber;  /* may be needed for error messages */
	switch (ls->t.token) {
	case TK_IF: {  /* stat -> ifstat */
		ifstat(ls, line);
		return 0;
				}
	case TK_WHILE: {  /* stat -> whilestat */
		whilestat(ls, line);
		return 0;
				   }
	case TK_DO: {  /* stat -> DO block END */
		luaX_next(ls);  /* skip DO */
		block(ls);
		check_match(ls, TK_END, TK_DO, line);
		return 0;
				}
	case TK_FOR: {  /* stat -> forstat */
		forstat(ls, line);
		return 0;
				 }
	case TK_REPEAT: {  /* stat -> repeatstat */
		repeatstat(ls, line);
		return 0;
					}
	case TK_FUNCTION: {
		funcstat(ls, line);  /* stat -> funcstat */
		return 0;
					  }
	case TK_LOCAL: {  /* stat -> localstat */
		luaX_next(ls);  /* skip LOCAL */
		if (testnext(ls, TK_FUNCTION))  /* local function? */
			localfunc(ls);
		else
			localstat(ls);
		return 0;
				   }
	case TK_RETURN: {  /* stat -> retstat */
		retstat(ls);
		return 1;  /* must be last statement */
					}
	case TK_BREAK: {  /* stat -> breakstat */
		luaX_next(ls);  /* skip BREAK */
		breakstat(ls);
		return 1;  /* must be last statement */
				   }
	default: {
		exprstat(ls);
		return 0;  /* to avoid warnings */
			 }
	}
}


static void chunk (LexState *ls) {
	/* chunk -> { stat [`;'] } */
	int islast = 0;
	enterlevel(ls);
	while (!islast && !block_follow(ls->t.token)) {
		islast = statement(ls);
		testnext(ls, ';');
		lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
			ls->fs->freereg >= ls->fs->nactvar);
		ls->fs->freereg = ls->fs->nactvar;  /* free registers */
	}
	leavelevel(ls);
}

/* }====================================================================== */
